home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / inn1.000 / inn1.4sec-linux-src.tar / inn / innd / site.c < prev   
C/C++ Source or Header  |  1993-03-18  |  21KB  |  964 lines

  1. /*  $Revision: 1.34 $
  2. **
  3. **  Routines to implement site-feeding.  Mainly working with channels to
  4. **  do buffering and determine what to send.
  5. */
  6. #include "innd.h"
  7.  
  8.  
  9. #define SITEmovetohead(sp_) \
  10.     if (SITEhead != sp_) { \
  11.     if (SITEtail == sp_) { \
  12.         SITEtail = sp_->Prev; \
  13.         SITEtail->Next = NULL; \
  14.     } \
  15.     else { \
  16.         if (sp_->Prev) \
  17.         sp_->Prev->Next = sp_->Next; \
  18.         if (sp_->Next) \
  19.         sp_->Next->Prev = sp_->Prev; \
  20.     } \
  21.     sp_->Prev = NULL; \
  22.     sp_->Next = SITEhead->Next; \
  23.     SITEhead->Prev = sp_; \
  24.     SITEhead = sp_; \
  25.     } \
  26.     else
  27.  
  28. STATIC int    SITEcount;
  29. STATIC SITE    *SITEhead;
  30. STATIC SITE    *SITEtail;
  31. STATIC char    SITEshell[] = _PATH_SH;
  32.  
  33.  
  34. /*
  35. **  Called when input is ready to read.  Shouldn't happen.
  36. */
  37. /* ARGSUSED0 */
  38. STATIC FUNCTYPE
  39. SITEreader(cp)
  40.     CHANNEL    *cp;
  41. {
  42.     syslog(L_ERROR, "%s internal SITEreader", LogName);
  43. }
  44.  
  45.  
  46. /*
  47. **  Called when write is done.  No-op.
  48. */
  49. /* ARGSUSED0 */
  50. STATIC FUNCTYPE
  51. SITEwritedone(cp)
  52.     CHANNEL    *cp;
  53. {
  54. }
  55.  
  56.  
  57. /*
  58. **  Make a site start spooling.
  59. */
  60. STATIC BOOL
  61. SITEspool(sp, cp)
  62.     register SITE    *sp;
  63.     CHANNEL        *cp;
  64. {
  65.     int            i;
  66.     char        buff[SPOOLNAMEBUFF];
  67.     char        *name;
  68.  
  69.     name = sp->SpoolName;
  70.     i = open(name, O_APPEND | O_CREAT | O_WRONLY, BATCHFILE_MODE);
  71.     if (i < 0 && errno == EISDIR) {
  72.     FileGlue(buff, sp->SpoolName, '/', "togo");
  73.     name = buff;
  74.     i = open(buff, O_APPEND | O_CREAT | O_WRONLY, BATCHFILE_MODE);
  75.     }
  76.     if (i < 0) {
  77.     IOError("site batch file");
  78.     syslog(L_ERROR, "%s cant open %s %m", sp->Name, name);
  79.     sp->Channel = NULL;
  80.     return FALSE;
  81.     }
  82.     if (AmRoot)
  83.     xchown(name);
  84.     if (cp) {
  85.     cp->fd = i;
  86.     return TRUE;
  87.     }
  88.     sp->Channel = CHANcreate(i, CTfile, CSwriting, SITEreader, SITEwritedone);
  89.     if (sp->Channel == NULL) {
  90.     syslog(L_ERROR, "%s cant channel %m", sp->Name);
  91.     (void)close(i);
  92.     return FALSE;
  93.     }
  94.     WCHANset(sp->Channel, "", 0);
  95.     sp->Spooling = TRUE;
  96.     sp->Process = -1;
  97.     return TRUE;
  98. }
  99.  
  100.  
  101. /*
  102. **  Find the oldest "file feed" site and buffer it.
  103. */
  104. STATIC void
  105. SITEbufferoldest()
  106. {
  107.     register SITE    *sp;
  108.     register BUFFER    *bp;
  109.     register BUFFER    *out;
  110.  
  111.     /* Go backwards and find the oldest file. */
  112.     for (sp = SITEtail; sp; sp = sp->Prev)
  113.     if (sp->Type == FTfile)
  114.         break;
  115.     if (sp == NULL) {
  116.     syslog(L_ERROR, "%s internal no oldest site found", LogName);
  117.     return;
  118.     }
  119.  
  120.     /* Write out what we can. */
  121.     (void)WCHANflush(sp->Channel);
  122.  
  123.     /* Get a buffer for the site. */
  124.     sp->Buffered = TRUE;
  125.     bp = &sp->Buffer;
  126.     bp->Used = 0;
  127.     bp->Left = 0;
  128.     if (bp->Size == 0) {
  129.     bp->Size = sp->Flushpoint;
  130.     bp->Data = NEW(char, bp->Size);
  131.     }
  132.     else {
  133.     bp->Size = sp->Flushpoint;
  134.     RENEW(bp->Data, char, bp->Size);
  135.     }
  136.  
  137.     /* If there's any unwritten data, copy it. */
  138.     out = &sp->Channel->Out;
  139.     if (out->Left)
  140.     BUFFset(bp, &out->Data[out->Used], out->Left);
  141.  
  142.     /* Now close the original channel. */
  143.     CHANclose(sp->Channel, sp->Name);
  144.     SITEcount--;
  145. }
  146.  
  147.  
  148. /*
  149. **  Check if we need to write out the site's buffer.  If we're buffered
  150. **  or the feed is backed up, this gets a bit complicated.
  151. */
  152. STATIC void
  153. SITEflushcheck(sp, bp)
  154.     register SITE    *sp;
  155.     register BUFFER    *bp;
  156. {
  157.     register int    i;
  158.     register CHANNEL    *cp;
  159.  
  160.     /* If we're buffered, and we hit the flushpoint, do an LRU. */
  161.     if (sp->Buffered) {
  162.     if (bp->Used < sp->Flushpoint)
  163.         return;
  164.     if (SITEcount > MaxOutgoing)
  165.         SITEbufferoldest();
  166.     if (!SITEsetup(sp) || sp->Buffered) {
  167.         syslog(L_ERROR, "%s cant unbuffer %m", sp->Name);
  168.         return;
  169.     }
  170.     WCHANsetfrombuffer(sp->Channel, bp);
  171.     WCHANadd(sp->Channel);
  172.     }
  173.  
  174.     if (PROCneedscan)
  175.     PROCscan();
  176.  
  177.     /* Handle buffering. */
  178.     cp = sp->Channel;
  179.     i = cp->Out.Left;
  180.     if (i < sp->StopWriting)
  181.     WCHANremove(cp);
  182.     if ((sp->StartWriting == 0 || i > sp->StartWriting)
  183.      && !CHANsleeping(cp))
  184.     WCHANadd(cp);
  185.  
  186.     /* If we're a channel that's getting big, see if we need to spool. */
  187.     if (sp->Type == FTfile || sp->StartSpooling == 0 || i < sp->StartSpooling)
  188.     return;
  189.  
  190.     if (!SITEspool(sp, (CHANNEL *)NULL)) {
  191.     syslog(L_ERROR, "%s overflow %d bytes", sp->Name, i);
  192.     return;
  193.     }
  194.     syslog(L_ERROR, "%s spooling %d bytes", sp->Name, i);
  195.     WCHANsetfrombuffer(sp->Channel, &cp->Out);
  196.     WCHANadd(sp->Channel);
  197.     CHANclose(cp, CHANname(cp));
  198. }
  199.  
  200.  
  201. /*
  202. **  Send a control line to an exploder.
  203. */
  204. void
  205. SITEwrite(sp, text)
  206.     register SITE    *sp;
  207.     STRING        text;
  208. {
  209.     static char        PREFIX[] = { EXP_CONTROL, '\0' };
  210.     register BUFFER    *bp;
  211.  
  212.     if (sp->Buffered)
  213.     bp = &sp->Buffer;
  214.     else {
  215.     if (sp->Channel == NULL)
  216.         return;
  217.     bp = &sp->Channel->Out;
  218.     }
  219.     BUFFappend(bp, PREFIX, STRLEN(PREFIX));
  220.     BUFFappend(bp, text, (int)strlen(text));
  221.     BUFFappend(bp, "\n", 1);
  222.     WCHANadd(sp->Channel);
  223. }
  224.  
  225.  
  226. /*
  227. **  Send the desired data about an article down a channel.
  228. */
  229. STATIC void
  230. SITEwritefromflags(sp, Data)
  231.     register SITE    *sp;
  232.     ARTDATA        *Data;
  233. {
  234.     static char        ITEMSEP[] = " ";
  235.     static char        NL[] = "\n";
  236.     register char    *p;
  237.     register BOOL    Dirty;
  238.     register BUFFER    *bp;
  239.     register SITE    *spx;
  240.     register int    i;
  241.  
  242.     if (sp->Buffered)
  243.     bp = &sp->Buffer;
  244.     else {
  245.     /* This should not happen, but if we tried to spool and failed,
  246.      * e.g., because of a bad F param for this site, we can get
  247.      * into this state.  We already logged a message so give up. */
  248.     if (sp->Channel == NULL)
  249.         return;
  250.     bp = &sp->Channel->Out;
  251.     }
  252.     for (Dirty = FALSE, p = sp->FileFlags; *p; p++) {
  253.     switch (*p) {
  254.     default:
  255.         syslog(L_ERROR, "%s internal SITEwritefromflags %c", sp->Name, p);
  256.         continue;
  257.     case FEED_BYTESIZE:
  258.         if (Dirty)
  259.         BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  260.         BUFFappend(bp, Data->Size, Data->SizeLength);
  261.         break;
  262.     case FEED_FULLNAME:
  263.         if (Dirty)
  264.         BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  265.         BUFFappend(bp, SPOOL, SPOOLlen);
  266.         BUFFappend(bp, "/", 1);
  267.         BUFFappend(bp, Data->Name, Data->NameLength);
  268.         break;
  269.     case FEED_HDR_DISTRIB:
  270.         if (Dirty)
  271.         BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  272.         BUFFappend(bp, Data->Distribution, Data->DistributionLength);
  273.         break;
  274.     case FEED_HDR_NEWSGROUP:
  275.         if (Dirty)
  276.         BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  277.         BUFFappend(bp, Data->Newsgroups, Data->NewsgroupsLength);
  278.         break;
  279.     case FEED_HEADERS:
  280.         if (Dirty)
  281.         BUFFappend(bp, NL, STRLEN(NL));
  282.         BUFFappend(bp, Data->Headers->Data, Data->Headers->Left);
  283.         break;
  284.     case FEED_OVERVIEW:
  285.         if (Dirty)
  286.         BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  287.         BUFFappend(bp, Data->Overview->Data, Data->Overview->Left);
  288.         break;
  289.     case FEED_REPLIC:
  290.         if (Dirty)
  291.         BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  292.         BUFFappend(bp, Data->Replic, Data->ReplicLength);
  293.         break;
  294.     case FEED_TIMERECEIVED:
  295.         if (Dirty)
  296.         BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  297.         BUFFappend(bp, Data->TimeReceived, Data->TimeReceivedLength);
  298.         break;
  299.     case FEED_MESSAGEID:
  300.         if (Dirty)
  301.         BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  302.         BUFFappend(bp, Data->MessageID, Data->MessageIDLength);
  303.         break;
  304.     case FEED_FNLNAMES:
  305.         if (sp->FNLnames.Data) {
  306.         /* Funnel; write names of our sites that got it. */
  307.         if (Dirty)
  308.             BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  309.         BUFFappend(bp, sp->FNLnames.Data, sp->FNLnames.Used);
  310.         }
  311.         else {
  312.         /* Not funnel; write names of all sites that got it. */
  313.         for (spx = Sites, i = nSites; --i >= 0; spx++)
  314.             if (spx->Sendit) {
  315.             if (Dirty)
  316.                 BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  317.             BUFFappend(bp, spx->Name, spx->NameLength);
  318.             Dirty = TRUE;
  319.             }
  320.         }
  321.         break;
  322.     case FEED_NAME:
  323.         if (Dirty)
  324.         BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  325.         BUFFappend(bp, Data->Name, Data->NameLength);
  326.         break;
  327.     case FEED_NEWSGROUP:
  328.         if (Dirty)
  329.         BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  330.         if (sp->ng)
  331.         BUFFappend(bp, sp->ng->Name, sp->ng->NameLength);
  332.         else
  333.         BUFFappend(bp, "?", 1);
  334.         break;
  335.     case FEED_SITE:
  336.         if (Dirty)
  337.         BUFFappend(bp, ITEMSEP, STRLEN(ITEMSEP));
  338.         BUFFappend(bp, Data->Feedsite, Data->FeedsiteLength);
  339.         break;
  340.     }
  341.     Dirty = TRUE;
  342.     }
  343.     if (Dirty) {
  344.     BUFFappend(bp, "\n", 1);
  345.     SITEflushcheck(sp, bp);
  346.     }
  347. }
  348.  
  349.  
  350. /*
  351. **  Send one article to a site.
  352. */
  353. void
  354. SITEsend(sp, Data)
  355.     register SITE    *sp;
  356.     ARTDATA        *Data;
  357. {
  358.     register int    i;
  359.     register char    *p;
  360.     char        *temp;
  361.     char        buff[BUFSIZ];
  362.     STRING        argv[MAX_BUILTIN_ARGV];
  363.     int            fd;
  364.  
  365.     switch (sp->Type) {
  366.     default:
  367.     syslog(L_ERROR, "%s internal SITEsend type %d", sp->Name, sp->Type);
  368.     break;
  369.     case FTlogonly:
  370.     break;
  371.     case FTfunnel:
  372.     syslog(L_ERROR, "%s funnel_send", sp->Name);
  373.     break;
  374.     case FTfile:
  375.     if (SITEcount > MaxOutgoing)
  376.         SITEmovetohead(sp);
  377.     /* FALLTHROUGH */
  378.     case FTchannel:
  379.     case FTexploder:
  380.     SITEwritefromflags(sp, Data);
  381.     break;
  382.     case FTprogram:
  383.     /* Set up the argument vector. */
  384.     if (sp->FNLwantsnames) {
  385.         i = strlen(sp->Param) + sp->FNLnames.Used;
  386.         if (i + strlen(Data->Name) >= sizeof buff) {
  387.         syslog(L_ERROR, "%s toolong need %d for %s",
  388.             sp->Name, i + strlen(Data->Name), Data->Name);
  389.         break;
  390.         }
  391.         temp = NEW(char, i + 1);
  392.         p = strchr(sp->Param, '*');
  393.         *p = '\0';
  394.         (void)strcpy(temp, sp->Param);
  395.         (void)strcat(temp, sp->FNLnames.Data);
  396.         (void)strcat(temp, &p[1]);
  397.         *p = '*';
  398.         (void)sprintf(buff, temp, Data->Name);
  399.         DISPOSE(temp);
  400.     }
  401.     else
  402.         (void)sprintf(buff, sp->Param, Data->Name);
  403.  
  404.     if (NeedShell(buff, argv, ENDOF(argv))) {
  405.         argv[0] = SITEshell;
  406.         argv[1] = "-c";
  407.         argv[2] = buff;
  408.         argv[3] = NULL;
  409.     }
  410.  
  411.     /* Feed the article on standard input. */
  412.     fd = open(Data->Name, O_RDONLY);
  413.     if (fd < 0) {
  414.         /* Unlikely, but we could check if the article is cross-posted
  415.          * and try it under other names... */
  416.         syslog(L_ERROR, "%s cant open %s %m", sp->Name, Data->Name);
  417.         fd = 0;
  418.     }
  419.  
  420.     /* Start the process. */
  421.     i = Spawn(fd, (int)fileno(Errlog), (int)fileno(Errlog), argv);
  422.     if (i >= 0)
  423.         (void)PROCwatch(i, -1);
  424.     if (fd != 0)
  425.         (void)close(fd);
  426.     break;
  427.     }
  428. }
  429.  
  430.  
  431. /*
  432. **  The channel was sleeping because we had to spool our output to
  433. **  a file.  Flush and restart.
  434. */
  435. STATIC FUNCTYPE
  436. SITEspoolwake(cp)
  437.     CHANNEL    *cp;
  438. {
  439.     SITE    *sp;
  440.     int        *ip;
  441.  
  442.     ip = CAST(int*, cp->Argument);
  443.     sp = &Sites[*ip];
  444.     DISPOSE(cp->Argument);
  445.     cp->Argument = NULL;
  446.     if (sp->Channel != cp) {
  447.     syslog(L_ERROR, "%s internal SITEspoolwake %s got %d, not %d",
  448.         LogName, sp->Name, cp->fd, sp->Channel->fd);
  449.         return;
  450.     }
  451.     syslog(L_NOTICE, "%s spoolwake", sp->Name);
  452.     SITEflush(sp, TRUE);
  453. }
  454.  
  455.  
  456. /*
  457. **  Start up a process for a channel, or a spool to a file if we can't.
  458. **  Create a channel for the site to talk to.
  459. */
  460. STATIC BOOL
  461. SITEstartprocess(sp)
  462.     SITE        *sp;
  463. {
  464.     register int    i;
  465.     STRING        argv[MAX_BUILTIN_ARGV];
  466.     char        *process;
  467.     int            *ip;
  468.     int            pan[2];
  469.  
  470.     /* Create a pipe. */
  471.     if (pipe(pan) < 0) {
  472.     syslog(L_ERROR, "%s cant pipe %m", sp->Name);
  473.     return FALSE;
  474.     }
  475.     CloseOnExec(pan[PIPE_WRITE], TRUE);
  476.  
  477.     /* Set up the argument vector. */
  478.     process = COPY(sp->Param);
  479.     if (NeedShell(process, argv, ENDOF(argv))) {
  480.     argv[0] = SITEshell;
  481.     argv[1] = "-c";
  482.     argv[2] = process;
  483.     argv[3] = NULL;
  484.     }
  485.  
  486.     /* Fork a child. */
  487.     i = Spawn(pan[PIPE_READ], (int)fileno(Errlog), (int)fileno(Errlog), argv);
  488.     if (i > 0) {
  489.     sp->pid = i;
  490.     sp->Spooling = FALSE;
  491.     sp->Process = PROCwatch(i, sp - Sites);
  492.     (void)close(pan[PIPE_READ]);
  493.     sp->Channel = CHANcreate(pan[PIPE_WRITE],
  494.             sp->Type == FTchannel ? CTprocess : CTexploder,
  495.             CSwriting, SITEreader, SITEwritedone);
  496.     DISPOSE(process);
  497.     return TRUE;
  498.     }
  499.     DISPOSE(process);
  500.  
  501.     /* Error.  Switch to spooling. */
  502.     syslog(L_ERROR, "%s spooling", sp->Name);
  503.     (void)close(pan[PIPE_WRITE]);
  504.     (void)close(pan[PIPE_READ]);
  505.     if (!SITEspool(sp, (CHANNEL *)NULL))
  506.     return FALSE;
  507.  
  508.     /* We'll try to restart the channel later. */
  509.     syslog(L_ERROR, "%s cant spawn spooling %m", sp->Name);
  510.     ip = NEW(int, 1);
  511.     *ip = sp - Sites;
  512.     SCHANadd(sp->Channel, (time_t)(Now.time + CHANNEL_RETRY_TIME),
  513.     (POINTER)NULL, SITEspoolwake, (POINTER)ip);
  514.     return TRUE;
  515. }
  516.  
  517.  
  518. /*
  519. **  Set up a site for internal buffering.
  520. */
  521. STATIC void
  522. SITEbuffer(sp)
  523.     register SITE    *sp;
  524. {
  525.     register BUFFER    *bp;
  526.  
  527.     sp->Buffered = TRUE;
  528.     sp->Channel = NULL;
  529.     bp = &sp->Buffer;
  530.     if (bp->Size == 0) {
  531.     bp->Size = sp->Flushpoint;
  532.     bp->Data = NEW(char, bp->Size);
  533.     }
  534.     else {
  535.     bp->Size = sp->Flushpoint;
  536.     RENEW(bp->Data, char, bp->Size);
  537.     }
  538.     BUFFset(bp, "", 0);
  539.     syslog(L_NOTICE, "%s buffered", sp->Name);
  540. }
  541.  
  542.  
  543. /*
  544. **  Set up a site's feed.  This means opening a file or channel if needed.
  545. */
  546. BOOL
  547. SITEsetup(sp)
  548.     register SITE    *sp;
  549. {
  550.     int            fd;
  551.  
  552.     switch (sp->Type) {
  553.     default:
  554.     syslog(L_ERROR, "%s internal SITEsetup %d",
  555.         sp->Name, sp->Type);
  556.     return FALSE;
  557.     case FTfunnel:
  558.     case FTlogonly:
  559.     case FTprogram:
  560.     /* Nothing to do here. */
  561.     break;
  562.     case FTfile:
  563.     SITEcount++;
  564.     if (SITEcount > MaxOutgoing)
  565.         SITEbuffer(sp);
  566.     else {
  567.         sp->Buffered = FALSE;
  568.         fd = open(sp->Param, O_APPEND | O_CREAT | O_WRONLY, BATCHFILE_MODE);
  569.         if (fd < 0) {
  570.         if (errno == EMFILE) {
  571.             SITEbuffer(sp);
  572.             break;
  573.         }
  574.         IOError("site file");
  575.         syslog(L_NOTICE, "%s cant open %s %m", sp->Name, sp->Param);
  576.         return FALSE;
  577.         }
  578.         if (AmRoot)
  579.         xchown(sp->Param);
  580.         sp->Channel = CHANcreate(fd, CTfile, CSwriting,
  581.                 SITEreader, SITEwritedone);
  582.         syslog(L_NOTICE, "%s opened %s", sp->Name, CHANname(sp->Channel));
  583.         WCHANset(sp->Channel, "", 0);
  584.     }
  585.     break;
  586.     case FTchannel:
  587.     case FTexploder:
  588.     if (!SITEstartprocess(sp))
  589.         return FALSE;
  590.     syslog(L_NOTICE, "%s spawned %s", sp->Name, CHANname(sp->Channel));
  591.     WCHANset(sp->Channel, "", 0);
  592.     WCHANadd(sp->Channel);
  593.     break;
  594.     }
  595.     return TRUE;
  596. }
  597.  
  598.  
  599. /*
  600. **  A site's channel process died; restart it.
  601. */
  602. void
  603. SITEprocdied(sp, process, pp)
  604.     SITE    *sp;
  605.     int        process;
  606.     PROCESS    *pp;
  607. {
  608.     syslog(pp->Status ? L_ERROR : L_NOTICE, "%s exit %d elapsed %ld pid %ld",
  609.     sp->Name ? sp->Name : "?", pp->Status,
  610.     (pp->Collected - pp->Started) / 60L, (long)pp->Pid);
  611.     if (sp->Process != process || sp->Name == NULL)
  612.     /* We already started a new process for this channel
  613.      * or this site has been dropped. */
  614.     return;
  615.     if (sp->Channel != NULL)
  616.     CHANclose(sp->Channel, CHANname(sp->Channel));
  617.     sp->Working = SITEsetup(sp);
  618.     if (!sp->Working) {
  619.     syslog(L_ERROR, "%s cant restart %m", sp->Name);
  620.     return;
  621.     }
  622.     syslog(L_NOTICE, "%s restarted", sp->Name);
  623. }
  624.  
  625. /*
  626. **  A channel is about to be closed; see if any site cares.
  627. */
  628. void
  629. SITEchanclose(cp)
  630.     register CHANNEL    *cp;
  631. {
  632.     register int    i;
  633.     register SITE    *sp;
  634.     int            *ip;
  635.  
  636.     for (i = nSites, sp = Sites; --i >= 0; sp++)
  637.     if (sp->Channel == cp) {
  638.         /* Found the site that has this channel.  Start that
  639.          * site spooling, copy any data that might be pending,
  640.          * and arrange to retry later. */
  641.         if (!SITEspool(sp, (CHANNEL *)NULL)) {
  642.         syslog(L_ERROR, "%s loss %d bytes", sp->Name, i);
  643.         return;
  644.         }
  645.         WCHANsetfrombuffer(sp->Channel, &cp->Out);
  646.         WCHANadd(sp->Channel);
  647.         ip = NEW(int, 1);
  648.         *ip = sp - Sites;
  649.         SCHANadd(sp->Channel, (time_t)(Now.time + CHANNEL_RETRY_TIME),
  650.         (POINTER)NULL, SITEspoolwake, (POINTER)ip);
  651.         break;
  652.     }
  653. }
  654.  
  655.  
  656. /*
  657. **  Flush any pending data waiting to be sent.
  658. */
  659. void
  660. SITEflush(sp, Restart)
  661.     register SITE    *sp;
  662.     BOOL        Restart;
  663. {
  664.     register CHANNEL    *cp;
  665.     register BUFFER    *out;
  666.  
  667.     if (sp->Name == NULL)
  668.     return;
  669.  
  670.     SITEforward(sp, "flush");
  671.     switch (sp->Type) {
  672.     default:
  673.     syslog(L_ERROR, "%s internal SITEflush %d", sp->Name, sp->Type);
  674.     return;
  675.  
  676.     case FTlogonly:
  677.     case FTprogram:
  678.     case FTfunnel:
  679.     /* Nothing to do here. */
  680.     return;
  681.  
  682.     case FTchannel:
  683.     case FTexploder:
  684.     /* If spooling, close the file right now. */
  685.     if (sp->Spooling && (cp = sp->Channel) != NULL) {
  686.         (void)WCHANflush(cp);
  687.         CHANclose(cp, CHANname(cp));
  688.         sp->Channel = NULL;
  689.     }
  690.     break;
  691.  
  692.     case FTfile:
  693.     break;
  694.     }
  695.  
  696.     /* We're only dealing with files and channels now. */
  697.     if ((cp = sp->Channel) != NULL)
  698.     (void)WCHANflush(cp);
  699.  
  700.     /* Restart the site, copy any pending data. */
  701.     if (Restart) {
  702.     if (!SITEsetup(sp))
  703.         syslog(L_ERROR, "%s cant restart %m", sp->Name);
  704.     else if (cp != NULL) {
  705.         if (sp->Buffered) {
  706.         /* SITEsetup had to buffer us; save any residue. */
  707.         out = &sp->Channel->Out;
  708.             if (out->Left)
  709.             BUFFset(&sp->Buffer, &out->Data[out->Used], out->Left);
  710.         }
  711.         else
  712.         WCHANsetfrombuffer(sp->Channel, &cp->Out);
  713.     }
  714.     }
  715.     else if (cp != NULL && cp->Out.Left) {
  716.      if (sp->Type == FTfile || sp->Spooling) {
  717.         /* Can't flush a file?  Hopeless. */
  718.          syslog(L_ERROR, "%s dataloss %d", sp->Name, cp->Out.Left);
  719.          return;
  720.      }
  721.      /* Must be a working channel; spool and retry. */
  722.     syslog(L_ERROR, "%s spooling %d bytes", sp->Name, cp->Out.Left);
  723.      if (SITEspool(sp, cp))
  724.         SITEflush(sp, FALSE);
  725.      return;
  726.     }
  727.  
  728.     /* Close the old channel if it was open. */
  729.     if (cp != NULL) {
  730.         /* Make sure we have no dangling pointers to it. */
  731.     if (!Restart)
  732.         sp->Channel = NULL;
  733.     CHANclose(cp, sp->Name);
  734.     if (sp->Type == FTfile)
  735.         SITEcount--;
  736.     }
  737. }
  738.  
  739.  
  740. /*
  741. **  Flush all sites.
  742. */
  743. void
  744. SITEflushall(Restart)
  745.     BOOL    Restart;
  746. {
  747.     register int    i;
  748.     register SITE    *sp;
  749.  
  750.     for (i = nSites, sp = Sites; --i >= 0; sp++)
  751.     if (sp->Name)
  752.         SITEflush(sp, Restart);
  753. }
  754.  
  755.  
  756. /*
  757. **  Run down the site's pattern list and see if it wants the specified
  758. **  newsgroup.
  759. */
  760. BOOL
  761. SITEwantsgroup(sp, name)
  762.     register SITE    *sp;
  763.     register char    *name;
  764. {
  765.     register BOOL    match;
  766.     register BOOL    subvalue;
  767.     register char    *pat;
  768.     register char    **argv;
  769.  
  770.     match = SUB_DEFAULT;
  771.     if (ME.Patterns) {
  772.     for (argv = ME.Patterns; (pat = *argv++) != NULL; ) {
  773.         subvalue = *pat != SUB_NEGATE;
  774.         if (!subvalue)
  775.         pat++;
  776.         if (wildmat(name, pat))
  777.         match = subvalue;
  778.     }
  779.     }
  780.     for (argv = sp->Patterns; (pat = *argv++) != NULL; ) {
  781.     subvalue = *pat != SUB_NEGATE;
  782.     if (!subvalue)
  783.         pat++;
  784.     if (wildmat(name, pat))
  785.         match = subvalue;
  786.     }
  787.     return match;
  788. }
  789.  
  790.  
  791. /*
  792. **  Find a site.
  793. */
  794. SITE *
  795. SITEfind(p)
  796.     char    *p;
  797. {
  798.     register int    i;
  799.     register SITE    *sp;
  800.  
  801.     for (i = nSites, sp = Sites; --i >= 0; sp++)
  802.     if (sp->Name && caseEQ(p, sp->Name))
  803.         return sp;
  804.     return NULL;
  805. }
  806.  
  807.  
  808. /*
  809. **  Find the next site that matches this site.
  810. */
  811. SITE *
  812. SITEfindnext(p, sp)
  813.     char        *p;
  814.     register SITE    *sp;
  815. {
  816.     register SITE    *end;
  817.  
  818.     for (sp++, end = &Sites[nSites]; sp < end; sp++)
  819.     if (sp->Name && caseEQ(p, sp->Name))
  820.         return sp;
  821.     return NULL;
  822. }
  823.  
  824.  
  825. /*
  826. **  Close a site down.
  827. */
  828. void
  829. SITEfree(sp)
  830.     register SITE    *sp;
  831. {
  832.     register SITE    *s;
  833.     register int    new;
  834.     register int    i;
  835.  
  836.     if (sp->Channel) {
  837.     CHANclose(sp->Channel, CHANname(sp->Channel));
  838.     sp->Channel = NULL;
  839.     }
  840.     sp->Name = NULL;
  841.     if (sp->Process > 0) {
  842.     /* Kill the backpointer so PROCdied won't call us. */
  843.     PROCunwatch(sp->Process);
  844.     sp->Process = -1;
  845.     }
  846.     if (sp->Entry) {
  847.     DISPOSE(sp->Entry);
  848.     sp->Entry = NULL;
  849.     }
  850.     if (sp->Param) {
  851.     DISPOSE(sp->Param);
  852.     sp->Param = NULL;
  853.     }
  854.     if (sp->SpoolName) {
  855.     DISPOSE(sp->SpoolName);
  856.     sp->SpoolName = NULL;
  857.     }
  858.     if (sp->Patterns) {
  859.     DISPOSE(sp->Patterns);
  860.     sp->Patterns = NULL;
  861.     }
  862.     if (sp->Exclusions) {
  863.     DISPOSE(sp->Exclusions);
  864.     sp->Exclusions = NULL;
  865.     }
  866.     if (sp->Distributions) {
  867.     DISPOSE(sp->Distributions);
  868.     sp->Distributions = NULL;
  869.     }
  870.     if (sp->Buffer.Data) {
  871.     DISPOSE(sp->Buffer.Data);
  872.     sp->Buffer.Data = NULL;
  873.     sp->Buffer.Size = 0;
  874.     }
  875.     if (sp->FNLnames.Data) {
  876.     DISPOSE(sp->FNLnames.Data);
  877.     sp->FNLnames.Data = NULL;
  878.     sp->FNLnames.Size = 0;
  879.     }
  880.  
  881.     /* If this site was a master, find a new one. */
  882.     if (sp->IsMaster) {
  883.     for (new = NOSITE, s = Sites, i = nSites; --i >= 0; s++)
  884.         if (&Sites[s->Master] == sp)
  885.         if (new == NOSITE) {
  886.             s->Master = NOSITE;
  887.             s->IsMaster = TRUE;
  888.             new = s - Sites;
  889.         }
  890.         else
  891.             s->Master = new;
  892.     sp->IsMaster = FALSE;
  893.     }
  894. }
  895.  
  896.  
  897. /*
  898. **  If a site is an exploder or funnels into one, forward a command
  899. **  to it.
  900. */
  901. void
  902. SITEforward(sp, text)
  903.     register SITE    *sp;
  904.     char        *text;
  905. {
  906.     register SITE    *fsp;
  907.     register char    *p;
  908.     char        buff[SMBUF];
  909.  
  910.     fsp = sp;
  911.     if (sp->Name == NULL || fsp->Name == NULL)
  912.     return;
  913.     if (fsp->Funnel != NOSITE)
  914.     fsp = &Sites[fsp->Funnel];
  915.     if (fsp->Type == FTexploder) {
  916.     (void)strcpy(buff, text);
  917.     if (fsp != sp && fsp->FNLwantsnames) {
  918.         p = buff + strlen(buff);
  919.         *p++ = ' ';
  920.         (void)strcpy(p, sp->Name);
  921.     }
  922.     SITEwrite(fsp, buff);
  923.     }
  924. }
  925.  
  926.  
  927. /*
  928. **  Drop a site.
  929. */
  930. void
  931. SITEdrop(sp)
  932.     SITE        *sp;
  933. {
  934.     SITEforward(sp, "drop");
  935.     SITEflush(sp, FALSE);
  936.     SITEfree(sp);
  937.     sp->Name = NULL;
  938.     SITElinkall();
  939. }
  940.  
  941.  
  942. /*
  943. **  Put all the feeds into a doubly-linked list.
  944. */
  945. void
  946. SITElinkall()
  947. {
  948.     register SITE    *sp;
  949.  
  950.     if (nSites < 2)
  951.     return;
  952.  
  953.     SITEhead = &Sites[0];
  954.     SITEtail = &Sites[nSites - 1];
  955.     for (sp = SITEhead; ++sp < SITEtail; )
  956.     sp[-1].Next = sp[1].Prev = sp;
  957.     SITEhead->Prev = NULL;
  958.     if (SITEhead->Next)
  959.     SITEhead->Next->Prev = SITEhead;
  960.     SITEtail->Next = NULL;
  961.     if (SITEtail->Prev)
  962.     SITEtail->Prev->Next = SITEtail;
  963. }
  964.